package com.netsdk.demo.customize;

import com.netsdk.demo.customize.healthCodeEx.callback.RegisterServiceCallBack;
import com.netsdk.demo.customize.healthCodeEx.entity.DeviceInfo;
import com.netsdk.demo.customize.healthCodeEx.entity.ListenInfo;
import com.netsdk.demo.customize.healthCodeEx.module.AutoRegisterModule;
import com.netsdk.demo.customize.healthCodeEx.module.LoginModule;
import com.netsdk.demo.customize.healthCodeEx.module.SdkUtilModule;
import com.netsdk.demo.util.CaseMenu;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.netsdk.lib.enumeration.EM_WATER_DETECTION_ALARM_TYPE;
import com.netsdk.lib.enumeration.ENUMERROR;
import com.netsdk.lib.structure.*;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;

import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author 291189
 * @version 1.0
 * @description
 * @date 2022/8/22 9:56
 */
public class WaterDataDemo {
    static NetSDKLib netSdk = NetSDKLib.NETSDK_INSTANCE;

    // 登录句柄
    private static NetSDKLib.LLong loginHandle = new NetSDKLib.LLong(0);

    // 设备信息
    private static NetSDKLib.NET_DEVICEINFO_Ex m_hDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
    // 主动注册监听句柄
    private NetSDKLib.LLong m_hListenHandle = new NetSDKLib.LLong(0);

    // 用户存储注册上来的设备信息的缓存 Map 项目中请替换成其他中间件
    private final Map<String, DeviceInfo> deviceInfoMap = new ConcurrentHashMap<>();

    private volatile Boolean taskIsOpen = false;

    /////////////// 注册地址(服务器 这里是运行此Demo的电脑IP) 监听端口 //////////////////////
    private final String serverIpAddr = "10.34.3.159";
    private final int serverPort = 9500; // 注意不要和其他程序发生冲突
    private String username = "admin";
    private String password = "admin123";

    /////////////// 配置TCP登陆地址，端口，用户名，密码 ////////////////////////
    private String m_ipAddr = "172.30.2.91";
    private int m_nPort = 37777;
    private String m_username = "admin";
    private String m_password = "admin123";
    //////////////////////////////////////////////////////////////////////
    public void GetWaterDataStatServerCaps(){

        NET_IN_WATERDATA_STAT_SERVER_GETCAPS_INFO input=new NET_IN_WATERDATA_STAT_SERVER_GETCAPS_INFO();
        Pointer pointerInput = new Memory(input.size());
        pointerInput.clear(input.size());

        ToolKits.SetStructDataToPointer(input, pointerInput, 0);

        NET_OUT_WATERDATA_STAT_SERVER_GETCAPS_INFO outPut=new NET_OUT_WATERDATA_STAT_SERVER_GETCAPS_INFO();
        Pointer pointerOutput = new Memory(outPut.size());
        pointerOutput.clear(outPut.size());

        ToolKits.SetStructDataToPointer(outPut, pointerOutput, 0);


        NetSDKLib.LLong lLong
                = netSdk.CLIENT_GetWaterDataStatServerCaps(loginHandle, pointerInput, pointerOutput, 3000);

        if(lLong.longValue()!=0){
            System.out.printf(" CLIENT_GetWaterDataStatServerCaps Success\n");

            ToolKits.GetPointerDataToStruct(pointerOutput,0,outPut);
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.println("emSupport:"+ outPut.emSupport);

            System.out.println("emSupportLocalDataStore:"+ outPut.emSupportLocalDataStore);
        }else {
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);  //防止gc重复回收

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.printf("CLIENT_GetWaterDataStatServerCaps Failed!LastError = %s\n",
                    ToolKits.getErrorCode());
        }

    }



//水质检测实时数据获取
    public void GetWaterDataStatServerWaterData(){

        NET_IN_WATERDATA_STAT_SERVER_GETDATA_INFO input=new NET_IN_WATERDATA_STAT_SERVER_GETDATA_INFO();
        input.nTypeNum=1;
        input.emType[0]=1;

        Pointer pointerInput = new Memory(input.size());
        pointerInput.clear(input.size());

        ToolKits.SetStructDataToPointer(input, pointerInput, 0);

        NET_OUT_WATERDATA_STAT_SERVER_GETDATA_INFO outPut=new NET_OUT_WATERDATA_STAT_SERVER_GETDATA_INFO();
        Pointer pointerOutput = new Memory(outPut.size());
        pointerOutput.clear(outPut.size());

        ToolKits.SetStructDataToPointer(outPut, pointerOutput, 0);

        NetSDKLib.LLong lLong  = netSdk.CLIENT_GetWaterDataStatServerWaterData(loginHandle, pointerInput, pointerOutput, 3000);

        if(lLong.longValue()!=0){
            System.out.printf(" CLIENT_GetWaterDataStatServerWaterData Success\n");

            ToolKits.GetPointerDataToStruct(pointerOutput,0,outPut);
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.println("emQuality:"+ outPut.emQuality);

            NET_WATER_DETECTION_UPLOAD_INFO stuUploadInfo
                    = outPut.stuUploadInfo;

            System.out.println("stuUploadInfo:"+ stuUploadInfo.toString());

            int nFlunkTypeNum
                    = outPut.nFlunkTypeNum;

            int[] emFlunkType = outPut.emFlunkType;

            for(int i=0;i<nFlunkTypeNum;i++){
                System.out.println("["+i+"]:"+ emFlunkType[i]);
            }

        }else {
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);  //防止gc重复回收

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.printf("CLIENT_GetWaterDataStatServerWaterData Failed!LastError = %s\n",
                    ToolKits.getErrorCode());
        }

    }

    private  int token=0;
//开始水质检测报表数据查询
    public void StartFindWaterDataStatServer(){

        NET_IN_START_FIND_WATERDATA_STAT_SERVER_INFO input=new NET_IN_START_FIND_WATERDATA_STAT_SERVER_INFO();

        NET_START_FIND_WATERDATA_CONDITION stuCondition =new NET_START_FIND_WATERDATA_CONDITION();


        stuCondition.emType[0] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_QUALITY.getValue();
        stuCondition.emType[1] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_PH.getValue();
        stuCondition.emType[2] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_NTU.getValue();
        stuCondition.emType[3] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_NH3_N.getValue();
        stuCondition.emType[4] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_TN.getValue();
        stuCondition.emType[5] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_SD.getValue();
        stuCondition.emType[6] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_COD.getValue();
        stuCondition.emType[7] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_NN.getValue();
        stuCondition.emType[8] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_DO.getValue();
        stuCondition.emType[9] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_CHL_A.getValue();
        stuCondition.emType[10] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_TP.getValue();
        stuCondition.emType[11] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_CODMN.getValue();
        stuCondition.emType[12] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_SS.getValue();
        stuCondition.emType[13] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_BOD_5.getValue();
        stuCondition.emType[14] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_NO3_N.getValue();
        stuCondition.emType[15] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_TSI.getValue();
        stuCondition.emType[16] = EM_WATER_DETECTION_ALARM_TYPE.EM_WATER_DETECTION_ALARM_TYPE_SMELLY_LEVEL.getValue();
        stuCondition.nTypeNum = 17;


        NET_TIME_EX netTimeStart
                = new NET_TIME_EX();
        netTimeStart.setTime(2022,7,28,0,0,0);


        stuCondition.stuStartTime=netTimeStart;


        NET_TIME_EX netTimeEnd
                = new NET_TIME_EX();
        netTimeEnd.setTime(2022,8,23,15,0,0);

        stuCondition.stuEndTime=netTimeEnd;

        input.stuCondition=stuCondition;

        Pointer pointerInput = new Memory(input.size());
        pointerInput.clear(input.size());

        ToolKits.SetStructDataToPointer(input, pointerInput, 0);

        NET_OUT_START_FIND_WATERDATA_STAT_SERVER_INFO outPut=new NET_OUT_START_FIND_WATERDATA_STAT_SERVER_INFO();
        Pointer pointerOutput = new Memory(outPut.size());
        pointerOutput.clear(outPut.size());

        ToolKits.SetStructDataToPointer(outPut, pointerOutput, 0);

        NetSDKLib.LLong lLong = netSdk.CLIENT_StartFindWaterDataStatServer(loginHandle, pointerInput, pointerOutput, 3000);

        if(lLong.longValue()!=0){
            System.out.printf(" CLIENT_StartFindWaterDataStatServer Success\n");

            ToolKits.GetPointerDataToStruct(pointerOutput,0,outPut);
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);
            token=outPut.nToken;
            System.out.println("nToken:"+ outPut.nToken);

            System.out.println("nTotalCount:"+ outPut.nTotalCount);
        }else {
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);  //防止gc重复回收

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.printf("CLIENT_StartFindWaterDataStatServer Failed!LastError = %s\n",
                    ToolKits.getErrorCode());
        }
    }


    //水质检测报表数据查询
    public void DoFindWaterDataStatServer(){

        NET_IN_DO_FIND_WATERDATA_STAT_SERVER_INFO input=new NET_IN_DO_FIND_WATERDATA_STAT_SERVER_INFO();

        input.nToken=token;
        input.nBeginNumber=0;
        input.nCount=20;    //CLIENT_StartFindWaterDataStatServer 方法中的返回值 nTotalCount，若返回为0，则此处查询不到

        Pointer pointerInput = new Memory(input.size());
        pointerInput.clear(input.size());

        ToolKits.SetStructDataToPointer(input, pointerInput, 0);

        NET_OUT_DO_FIND_WATERDATA_STAT_SERVER_INFO outPut=new NET_OUT_DO_FIND_WATERDATA_STAT_SERVER_INFO();
        Pointer pointerOutput = new Memory(outPut.size());
        pointerOutput.clear(outPut.size());

        ToolKits.SetStructDataToPointer(outPut, pointerOutput, 0);

        NetSDKLib.LLong lLong
                = netSdk.CLIENT_DoFindWaterDataStatServer(loginHandle, pointerInput, pointerOutput, 3000);

        if(lLong.longValue()!=0){
            System.out.printf("CLIENT_DoFindWaterDataStatServer Success\n");

            ToolKits.GetPointerDataToStruct(pointerOutput,0,outPut);
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.println("nFound:"+ outPut.nFound);

            System.out.println("nInfoNum:"+ outPut.nInfoNum);
            NET_WATERDATA_STAT_SERVER_INFO[] stuInfo
                    = outPut.stuInfo;

            for (int i=0;i<outPut.nInfoNum;i++){

                NET_WATERDATA_STAT_SERVER_INFO info
                        = stuInfo[i];
                int emQuality = info.emQuality;
                System.out.println("emQuality:"+emQuality);
                NET_TIME_EX stuStartTime
                        = info.stuStartTime;

                System.out.println("stuStartTime:"+stuStartTime);
                NET_WATER_DETECTION_UPLOAD_INFO stuUploadInfo
                        = info.stuUploadInfo;
                System.out.println("stuUploadInfo:"+ stuUploadInfo.toString());
            }

        }else {
            Native.free(Pointer.nativeValue(pointerInput)); //清理内存
            Pointer.nativeValue(pointerInput, 0);  //防止gc重复回收

            Native.free(Pointer.nativeValue(pointerOutput));
            Pointer.nativeValue(pointerOutput, 0);

            System.out.printf("CLIENT_DoFindWaterDataStatServer Failed!LastError = %s\n",
                    ToolKits.getErrorCode());
        }
    }

//停止水质检测报表数据查询
public void StopFindWaterDataStatServer(){

    NET_IN_STOP_FIND_WATERDATA_STAT_SERVER_INFO input=new NET_IN_STOP_FIND_WATERDATA_STAT_SERVER_INFO();

    input.nToken=token;

    Pointer pointerInput = new Memory(input.size());
    pointerInput.clear(input.size());

    ToolKits.SetStructDataToPointer(input, pointerInput, 0);

    NET_OUT_STOP_FIND_WATERDATA_STAT_SERVER_INFO outPut=new NET_OUT_STOP_FIND_WATERDATA_STAT_SERVER_INFO();
    Pointer pointerOutput = new Memory(outPut.size());
    pointerOutput.clear(outPut.size());

    ToolKits.SetStructDataToPointer(outPut, pointerOutput, 0);

    NetSDKLib.LLong lLong
            = netSdk.CLIENT_StopFindWaterDataStatServer(loginHandle, pointerInput, pointerOutput, 3000);

    if(lLong.longValue()!=0){

        ToolKits.GetPointerDataToStruct(pointerOutput,0,outPut);
        Native.free(Pointer.nativeValue(pointerInput)); //清理内存
        Pointer.nativeValue(pointerInput, 0);

        Native.free(Pointer.nativeValue(pointerOutput));
        Pointer.nativeValue(pointerOutput, 0);
        System.out.printf("CLIENT_StopFindWaterDataStatServer Success\n");

    }else {
        Native.free(Pointer.nativeValue(pointerInput)); //清理内存
        Pointer.nativeValue(pointerInput, 0);  //防止gc重复回收

        Native.free(Pointer.nativeValue(pointerOutput));
        Pointer.nativeValue(pointerOutput, 0);

        System.out.printf("CLIENT_StopFindWaterDataStatServer Failed!LastError = %s\n",
                ToolKits.getErrorCode());
    }
}


    /**
     * 主动注册
     */
    public void autoRegisterLogin() {
        // 开启监听
        serverStartListen();
        // 登录设备
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入设备的注册 Serial：");
        String key = sc.nextLine().trim();

        DeviceInfo deviceInfo = deviceInfoMap.get(key);
        if (deviceInfo == null) {
            System.out.println("注册上报的设备中没有该 Serial");
            return;
        }

        // 注册设备的IP
        String ipAddr = deviceInfo.ipAddress;
        // 注册设备的端口
        int port = deviceInfo.port;
        // 账号
        String username = this.username;
        // 密码
        String password = this.password;

     loginHandle = LoginModule.AutoRegisterLoginWithHighSecurity(key, ipAddr, port, username,
                password, deviceInfo.m_stDeviceInfo);

        if (loginHandle.longValue() == 0) {
            System.err.println("主动注册登录失败:" + ENUMERROR.getErrorMessage());
            return;
        }
        loginHandle.setValue(loginHandle.longValue());
        // 清除此注册信息 请等待重新上报后再重新登录
        deviceInfoMap.remove(key);
    }
    /**
     * 初始化测试
     */
    public void InitTest() {
        // 初始化SDK库
        SdkUtilModule.Init();
        // 登录设备
        deviceLogin();
    }

    /**
     * 登录设备 两种登录方式 TCP登录 主动注册
     */
    public void deviceLogin() {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入登录方式   1 TCP登录    2 主动注册:");
        String key = sc.nextLine().trim();
        if ("1".equals(key)) {
            tcpLogin();
        } else if ("2".equals(key)) {
            autoRegisterLogin();
        } else {
            System.out.println("输入信息错误...");
        }
    }
    /**
     * TCP登录
     */
    public void tcpLogin() {
        loginHandle = LoginModule.TcpLoginWithHighSecurity(m_ipAddr, m_nPort, m_username, m_password,
                m_hDeviceInfo); // 高安全登录
        if (loginHandle.intValue() == 0) {
            System.err.println("TCP登录失败:" + ENUMERROR.getErrorMessage());
            return;
        }
        loginHandle.setValue(loginHandle.longValue());
    }
    /**
     * 开启监听
     */
    public void serverStartListen() {
        m_hListenHandle = AutoRegisterModule.ServerStartListen(serverIpAddr, serverPort,
                RegisterServiceCallBack.getInstance());
        if (m_hListenHandle.longValue() == 0)
            return;
        taskIsOpen = true;
        new Thread(this::eventListTask).start();
    }

    // 获取监听回调数据并放入缓存
    public void eventListTask() {
        while (taskIsOpen) {
            try {
                // 稍微延迟一下，避免循环的太快
                Thread.sleep(10);
                // 阻塞获取
                ListenInfo listenInfo = RegisterServiceCallBack.ServerInfoQueue.poll(50, TimeUnit.MILLISECONDS);
                if (listenInfo == null)
                    continue;
                // 结果放入缓存
                if (!deviceInfoMap.containsKey(listenInfo.devSerial)) {
                    deviceInfoMap.put(listenInfo.devSerial,
                            new DeviceInfo(listenInfo.devIpAddress, listenInfo.devPort));
                    System.out.println("...有新设备上报注册信息... Serial:" + listenInfo.devSerial);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 退出清理环境
     */
    public static void LoginOut(){
        System.out.println("End Test");
        if( loginHandle.longValue() != 0)
        {
            netSdk.CLIENT_Logout(loginHandle);
        }
        System.out.println("See You...");

        netSdk.CLIENT_Cleanup();
        System.exit(0);
    }

    public void RunTest()
    {
        System.out.println("Run Test");
        CaseMenu menu = new CaseMenu();
        menu.addItem((new CaseMenu.Item(this , "autoRegisterLogin" , "autoRegisterLogin")));
        menu.addItem((new CaseMenu.Item(this , "GetWaterDataStatServerCaps" , "GetWaterDataStatServerCaps")));
        menu.addItem((new CaseMenu.Item(this , "GetWaterDataStatServerWaterData" , "GetWaterDataStatServerWaterData")));
        menu.addItem((new CaseMenu.Item(this , "StartFindWaterDataStatServer" , "StartFindWaterDataStatServer")));
        menu.addItem((new CaseMenu.Item(this , "DoFindWaterDataStatServer" , "DoFindWaterDataStatServer")));
        menu.addItem((new CaseMenu.Item(this , "StopFindWaterDataStatServer" , "StopFindWaterDataStatServer")));
        menu.addItem((new CaseMenu.Item(this , "LoginOut" , "LoginOut")));
        menu.run();
    }

    public static void main(String[] args) {

        WaterDataDemo waterDataDemo=new WaterDataDemo();
        waterDataDemo.InitTest();
        waterDataDemo.RunTest();

    }
}
